import java.util.ArrayList;
import java.util.Random;

/**
 * @author Jesse McCane
 * @author Berkley Shands
 */

/*
 * This class deals with Computer player specific functionality
 */

public class Comp extends Player{
	private Random generator = new Random();

	private int bidDiffLevel, playDiffLevel;
	private boolean[] nilers, passers;
	private Card[] cardsPlayed;
	private int firstCard, numPlayed, trickNum, numNilers, numPassers,
			numBidders;
	boolean allBusted, allBidsMade;

	Comp(){
		this.myName = "Computer " + compCount;
		compCount++;
		this.bidDiffLevel = 0;
		this.playDiffLevel = 0;
		totalCount++;
		this.myIDNum = totalCount;
	}

	Comp(int bidlevel, int playlevel){
		this.myName = "Computer " + compCount;
		compCount++;
		this.bidDiffLevel = bidlevel;
		this.playDiffLevel = playlevel;
		totalCount++;
		this.myIDNum = totalCount;
	}

	public void setPlayableCards(Card[] cardsPlayed, int firstCard, int numPlayed){ //copied from human player
		playableCards = new ArrayList<Boolean>(myHand.size());
		this.cardsPlayed = cardsPlayed;
		this.firstCard = firstCard;
		this.numPlayed = numPlayed;

		if((Gameplay.roundTrump == Gameplay.ALLTRUMP) || (numPlayed == 0)){
			for(int i = 0; i < myHand.size(); i++){
				playableCards.add(i, true);
			}
			return;
		}
		for(int i = 0; i < myHand.size(); i++){
			if(myHand.get(i).isAOH()){
				playableCards.add(i, true);
			}else if(myHand.get(i).getSuit() == Gameplay.roundTrump){
				playableCards.add(i, true);
			}else if(cardsPlayed[firstCard].isAOH()){
				if(!(this.hasSuit(Gameplay.roundTrump))){
					playableCards.add(i, true);
				}else{
					playableCards.add(i, false);
				}
			}else{
				if(myHand.get(i).getSuit() == cardsPlayed[firstCard].getSuit()){
					playableCards.add(i, true);
				}else if(!(this.hasSuit(cardsPlayed[firstCard].getSuit()))){
					playableCards.add(i, true);
				}else{
					playableCards.add(i, false);
				}
			}
		}
	}

	public void displayPlayableHand(){ //dont need this later, but for testing now
		System.out.println(myName + "'s playable cards in this situation are:");
		for(int i = 0; i < myHand.size(); i++){
			if(playableCards.get(i)){
				System.out.println("" + (i + 1) + " - " + myHand.get(i).toString());
			}
		}
		System.out.println("");
	}

	public int bid(int maxTrump, int maxBid, int bCounter){
		doPass();
		bCounter++;

		return bCounter;
	}

	protected boolean doBid(int maxTrump, int maxBid){
		return false;
	}

	protected boolean doNil(int maxTrump, int maxBid){
		return false;
	}

	public void firstBid(){//shouldnt happen currently
	}

	public Card playTrick(){
		int cardNum = 0;
		int strat = 0;
		Card playedCard;

		this.trickNum++;
		this.displayPlayableHand(); //for testing

		if(playDiffLevel == 0){ //random card difficulty
			return playRandom();
		}
		if(playDiffLevel >= 1){//enable nil busting , otherwise take all
			if(numNilers > 0 && !allBusted){//we know some one niled so let's play accordingly to bust it
				strat = 1;
			}else{
				if(numPlayed == 0){//comp is first
					strat = 2;
				}else{
					strat = 3;
				}
			}
		}
		if(playDiffLevel >= 2){//computer will change strat mid fight if nil has been busted or a bid is made
			if(numNilers + numPassers == totalCount){ //only nilers and passers keep strat at 1
				strat = 1;
			}else if((strat == 2 || strat == 3) && allBidsMade){
				strat = 1;
			}
		}

		switch (strat){
			case 1:
				cardNum = playLowestRankCard();
				break;
			case 2:
				cardNum = playHighestRankCard();
				break;
			case 3:
				cardNum = playHighestCard();
				break;
		}

		playedCard = this.playCard(cardNum);

		return playedCard;
	}

	//plays the highest card available
	private int playHighestCard(){
		Card bestCard = null;
		Card tempCard;
		int cardNum = 0;

		for(int i = 0; i < myHand.size(); i++){
			if(playableCards.get(i) && bestCard != null){//card is playable
				tempCard = myHand.get(i);
				if(bestCard.compareTo(tempCard)){ //gets highest card
					bestCard = tempCard;
					cardNum = i;
				}
			}else if(playableCards.get(i) && bestCard == null){//first playable card seen
				bestCard = myHand.get(i);
				cardNum = i;
			}
		}

		return cardNum;
	}

	//plays the lowest ranked card available
	private int playLowestRankCard(){
		Card bestCard = null;
		Card tempCard;
		int cardNum = 0;

		for(int i = 0; i < myHand.size(); i++){
			if(playableCards.get(i) && bestCard != null){//card is playable
				tempCard = myHand.get(i);
				if(!bestCard.compareToGenaric(tempCard)){ //not because we want a lower card
					bestCard = tempCard;
					cardNum = i;
				}
			}else if(playableCards.get(i) && bestCard == null){//first playable card seen
				bestCard = myHand.get(i);
				cardNum = i;
			}
		}

		return cardNum;
	}

	//plays the highest ranked card available
	private int playHighestRankCard(){
		Card bestCard = null;
		Card tempCard;
		int cardNum = 0;

		for(int i = 0; i < myHand.size(); i++){
			if(playableCards.get(i) && bestCard != null){//card is playable
				tempCard = myHand.get(i);
				if(bestCard.compareToGenaric(tempCard)){ //gets highest card
					bestCard = tempCard;
					cardNum = i;
				}
			}else if(playableCards.get(i) && bestCard == null){//first playable card seen
				bestCard = myHand.get(i);
				cardNum = i;
			}
		}

		return cardNum;
	}

	private Card playRandom(){
		int cardNum;
		Card playedCard;

		do{
			cardNum = generator.nextInt(this.myHand.size());
		}while(!(this.playableCards.get(cardNum)));

		playedCard = this.playCard(cardNum); //-1 because cards are 0-X not 1-X+1

		return playedCard;
	}

	//this function will look at what players bid
	public void determineStrat(){
		this.trickNum = 0;
		Player ply;
		int callType;

		nilers = new boolean[totalCount];
		numNilers = 0;
		allBusted = false;

		passers = new boolean[totalCount];
		numPassers = 0;

		numBidders = 0;
		allBidsMade = false;

		for(int i = 0; i < totalCount; i++){
			ply = Gameplay.players.get(i);
			if(!this.equals(ply)){//dont want to count self
				callType = ply.getCallType();
				if(callType == Gameplay.NIL){
					nilers[i] = true;
					numNilers++;
				}else{
					nilers[i] = false;
				}
				if(callType == Gameplay.PASS){
					passers[i] = true;
					numPassers++;
				}else{
					passers[i] = false;
				}
				if(callType == Gameplay.BID){
					numBidders++;
				}
			}
		}
	}

	public void adjustRoundStrat(){
		int nilsBusted = 0;
		int bidsMade = 0;
		Player plyer;

		if(playDiffLevel >= 2){ //only check for busted nils on a higher level of ai
			for(int i = 0; i < totalCount; i++){ //counts the number of nils busted
				plyer = Gameplay.players.get(i);
				if(nilers[i] && plyer.getTricksTaken() > 0){
					nilsBusted++;
				}else if(plyer.getCallType() == Gameplay.BID && plyer.getTricksBid() <= plyer.getTricksTaken()){//counts number of people who have made their bid
					bidsMade++;
				}
			}
			if(nilsBusted == numNilers){
				allBusted = true;
			}
			if(bidsMade == numBidders){
				allBidsMade = true;
			}

		}
	}
}
